package adapletplugin.editors;

import objects.AdapletConstants;
import objects.IObject;
import objects.Interface;
import objects.Table;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;

import sections.ISection.Section;
import util.ISectionListener;
import adapletplugin.dialogs.NewAttributeDialog;

public class InterfaceEditor extends AbstractSubEditor implements ISectionListener
{
	private Text fInterfaceNameText;
	private Combo fTableText;
	private Combo fBaseObjectText;
	private Combo fBaseObjColText;

	private Interface interFocus;

	// TABLE for attributes
	private Button fNewAttributeButton;
	private TableViewer fAttributeTable;

	public InterfaceEditor(ScrolledComposite composite, FormToolkit toolkit, MapFileEditor parentEditor)
	{
		super(composite, toolkit, parentEditor);
		fMap.registerListener(Section.TABLE, this);
		fMap.registerListener(Section.TYPE, this);
		fMap.registerListener(Section.REF_TYPE, this);
	}

	@Override
	protected void create()
	{
		Composite row = fToolkit.createComposite(fSubComposite);
		row.setLayout(new GridLayout(2, false));
		row.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

		fToolkit.createLabel(row, "Interface Name:");
		fInterfaceNameText = fToolkit.createText(row, "", SWT.BORDER | SWT.READ_ONLY);
		fInterfaceNameText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
//		fInterfaceNameText.addModifyListener(createModifyListener_Name());

		fToolkit.createLabel(row, "Table Name:");
		fTableText = new Combo(row, SWT.BORDER);
		fTableText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fTableText.addModifyListener(createModifyListener_Table());

		fToolkit.createLabel(row, "Base Object:");
		fBaseObjectText = new Combo(row, SWT.BORDER);
		fBaseObjectText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fBaseObjectText.addModifyListener(createModifyListener_Base());

		fToolkit.createLabel(row, "Base Object Column:");
		fBaseObjColText = new Combo(row, SWT.BORDER);
		fBaseObjColText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		fBaseObjColText.addModifyListener(createModifyListener_BaseCol());

		fNewAttributeButton = fToolkit.createButton(fSubComposite, "Add Attribute", SWT.PUSH);
		fNewAttributeButton.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
		fNewAttributeButton.addSelectionListener(createNewAttributeListener());

		createAttributeTable();
	}

	private void createAttributeTable()
	{
		fAttributeTable = new TableViewer(fSubComposite, SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION);
		fAttributeTable.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		fAttributeTable.setContentProvider(new AttributeTableContentProvider());
		fAttributeTable.setColumnProperties(new String[] { "Attribute", "Table Column" });

		TableViewerColumn viewerColumn = new TableViewerColumn(fAttributeTable, SWT.NONE);
		TableColumn col = viewerColumn.getColumn();
		col.setMoveable(false);
		col.setResizable(true);
		col.setText("Attribute");
		col.setWidth(AdapletConstants.computeSubWidth(2, 2));
		viewerColumn.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element)
			{
				return (String) element;
			}
		});

		viewerColumn.setEditingSupport(new EditingSupport(fAttributeTable) {

			@Override
			protected void setValue(Object element, Object value)
			{
				String oldAttrName = (String) element;
				String newAttrName = (String) value;

				if (newAttrName == null || newAttrName.isEmpty())
				{
					return;
				}

				String[] allAttrNames = interFocus.getAttributeNames();
				for (String curAttrName : allAttrNames)
				{
					if (curAttrName.equals(newAttrName))
					{
						return;
					}
				}

				String oldAttrValue = interFocus.getAttributeColumn(oldAttrName);

				interFocus.removeAttribute(oldAttrName);
				interFocus.addAttribute(newAttrName, oldAttrValue);

				fEditor.refresh();
				fAttributeTable.refresh();
			}

			@Override
			protected Object getValue(Object element)
			{
				return element;
			}

			@Override
			protected CellEditor getCellEditor(Object element)
			{
				return new TextCellEditor(fAttributeTable.getTable());
			}

			@Override
			protected boolean canEdit(Object element)
			{
				return true;
			}
		});

		viewerColumn = new TableViewerColumn(fAttributeTable, SWT.NONE);
		col = viewerColumn.getColumn();
		col.setMoveable(false);
		col.setResizable(true);
		col.setText("Table Column");
		col.setWidth(AdapletConstants.computeSubWidth(2, 2));
		col.setAlignment(SWT.RIGHT);
		viewerColumn.setLabelProvider(new ColumnLabelProvider() {
			@Override
			public String getText(Object element)
			{
				return interFocus.getAttributeColumn((String) element);
			}
		});

		viewerColumn.setEditingSupport(new EditingSupport(fAttributeTable) {

			@Override
			protected void setValue(Object element, Object value)
			{
				interFocus.addAttribute((String) element, (String) value);
				fEditor.refresh();
				fAttributeTable.refresh();
			}

			@Override
			protected Object getValue(Object element)
			{
				return interFocus.getAttributeColumn((String) element);
			}

			@Override
			protected CellEditor getCellEditor(Object element)
			{
				return new TextCellEditor(fAttributeTable.getTable());
			}

			@Override
			protected boolean canEdit(Object element)
			{
				return true;
			}
		});

		fAttributeTable.getTable().setHeaderVisible(true);

		fAttributeTable.setInput(new AttributeTableInput(interFocus));

		createTableContextMenu();
	}

	private void createTableContextMenu()
	{
		Menu menu = new Menu(fAttributeTable.getTable());

		MenuItem item = new MenuItem(menu, SWT.PUSH);
		item.setText("Remove Attribute");
		item.addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e)
			{
				IStructuredSelection selection = (IStructuredSelection) fAttributeTable.getSelection();
				String attrName = (String) selection.getFirstElement();

				interFocus.removeAttribute(attrName);

				fAttributeTable.refresh();
				fEditor.refresh();
			}
		});

		fAttributeTable.getTable().setMenu(menu);
	}

	private SelectionListener createNewAttributeListener()
	{
		return new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e)
			{
				Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();

				NewAttributeDialog dialog = new NewAttributeDialog(shell, Section.INTERFACE, interFocus.getObjectName());

				dialog.create();
				dialog.open();

				if (dialog.getReturnCode() == Window.OK)
				{
					interFocus.addAttribute(dialog.getAttribute(), dialog.getColumn());

					fAttributeTable.refresh();
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_BaseCol()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (interFocus != null)
				{
					interFocus.setBaseObjectColumn(fBaseObjColText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Base()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (interFocus != null)
				{
					interFocus.setBaseObject(fBaseObjectText.getText());
					fEditor.refresh();
				}
			}
		};
	}

	private ModifyListener createModifyListener_Table()
	{
		return new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e)
			{
				if (interFocus != null)
				{
					interFocus.setTableName(fTableText.getText());
					populateColumnComboChoices();
					fEditor.refresh();
				}
			}
		};
	}

//	private ModifyListener createModifyListener_Name()
//	{
//		return new ModifyListener() {
//
//			@Override
//			public void modifyText(ModifyEvent e)
//			{
//				if (interFocus != null)
//				{
//					interFocus.setInterfaceName(fInterfaceNameText.getText());
//					fEditor.refresh();
//				}
//			}
//		};
//	}

	@Override
	protected void updateFields()
	{
		interFocus = (Interface) fFocusObject;

		if (interFocus == null)
		{
			fInterfaceNameText.setText("");
			fTableText.setText("");
			fBaseObjectText.setText("");
			fBaseObjColText.setText("");
		}
		else
		{
			fInterfaceNameText.setText(interFocus.getInterfaceName());
			fTableText.setText(interFocus.getTableName());
			fBaseObjectText.setText(interFocus.getBaseObject());
			fBaseObjColText.setText(interFocus.getBaseObjectColumn());
		}

		fAttributeTable.setInput(new AttributeTableInput(interFocus));

		populateTableComboChoices();
		populateColumnComboChoices();
		populateTypeComboChoices();
	}

	private void populateTypeComboChoices()
	{
		IObject[] typeNames = fMap.getTypeSection().getObjects();
		IObject[] refTypeNames = fMap.getReferenceTypeSection().getObjects();
		
		String[] joinedNames = new String[typeNames.length + refTypeNames.length];
		
		int i;
		for(i = 0; i < typeNames.length; i++)
		{
			joinedNames[i] = typeNames[i].getObjectName();
		}
		
		for(int j = 0; j < refTypeNames.length; j++)
		{
			joinedNames[i+j] = refTypeNames[j].getObjectName();
		}
		
		updateComboSelection(fBaseObjectText, joinedNames, interFocus == null ? "" : interFocus.getBaseObject());
	}

	private class AttributeTableContentProvider implements IStructuredContentProvider
	{

		@Override
		public void dispose()
		{

		}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
		{

		}

		@Override
		public Object[] getElements(Object inputElement)
		{
			return ((AttributeTableInput) inputElement).getData();
		}

	}

	private class AttributeTableInput
	{
		private Interface fInput;

		public AttributeTableInput(Interface inter)
		{
			fInput = inter;
		}

		public String[] getData()
		{
			if (fInput == null)
			{
				return new String[0];
			}
			return fInput.getAttributeNames();
		}
	}

	@Override
	public void acceptChange(Section changedSection)
	{
		switch (changedSection)
		{
		case TABLE:
			populateTableComboChoices();
			populateColumnComboChoices();
			break;
		case TYPE:	//$FALL-THROUGH$
		case REF_TYPE:
			populateTypeComboChoices();
			break;
		default:
			break;
		}
	}

	@Override
	protected void populateTableComboChoices()
	{
		IObject[] tables = fMap.getTableSection().getObjects();

		String currentText = fTableText.getText();

		fTableText.removeAll();

		for (IObject table : tables)
		{
			fTableText.add(table.getObjectName());
		}

		fTableText.setText(currentText);
	}

	@Override
	protected void populateColumnComboChoices()
	{
		String tableName = fTableText.getText();
		if(tableName == null || tableName.isEmpty())
		{
			setColumnNames(new String[0]);
			return;
		}
		
		Table table = fMap.getTableSection().getTable(tableName);
		if(table == null)
		{
			setColumnNames(new String[0]);
			return;
		}
		
		String[] columnNames = table.getColumnNames();
		
		setColumnNames(columnNames);
	}

	@Override
	protected void setColumnNames(String[] columnNames)
	{
		updateComboSelection(fBaseObjColText, columnNames, interFocus == null ? "" : interFocus.getBaseObjectColumn());
	}

}
